
#include "queue.h"

queue_t* queue_create()
{
    queue_t* result = malloc(sizeof(queue_t));
    result->sentinel = malloc(sizeof(linked_t));
    
    result->sentinel->next = result->sentinel;
    result->sentinel->prev = result->sentinel;
    result->sentinel->context = NULL;
    result->sentinel->id = SENTINEL;
    result->current = result->sentinel;
    return result;
}

void queue_insert(queue_t* queue, linked_t *new)
{
    CHECK_ARG(queue);
       CHECK_ARG(new);
    linked_t* node = queue->current->prev;
    if (!node->id == SENTINEL)
    {
        //printf("invalid node\n");
    }
    
    if (queue->current->id == SENTINEL)
    {
        new->next = queue->sentinel;
        new->prev = queue->sentinel;
        queue->sentinel->next = new;
        queue->sentinel->prev = new;
        queue->current = new;
        
    }
    else
    {
        linked_t* next = queue->sentinel->next;
        
        next->prev = new;
        new->next = next;
        queue->sentinel->next = new;
        new->prev = queue->sentinel;
        
    }
}

void queue_push_context(queue_t* queue, ucontext_t* context, int priority)
{
    linked_t* new = linked_create(context, priority);
    queue_insert(queue, new);
}

linked_t* queue_pop(queue_t* queue)
{
    
    linked_t* result = queue->current;
    
    if (result->id == SENTINEL)
    {
        fprintf(stderr, "Removed from empty queue\n");
        exit(1);
    }
    linked_t* prev = result->prev;
    queue->current = prev;
    prev->next = queue->sentinel;
    return result;
}

void queue_rev_print(queue_t* queue)
{
    linked_t* current = queue->sentinel;
    printf("(Reverse) Sentinel -> ");
    fflush(stdout);
    current = current->prev;
    while(current->id != SENTINEL)
    {
        printf("(%d) -> ", current->id);
        fflush(stdout);
        current = current->prev;
    }
    printf("\n");
    
}

void queue_print(queue_t* queue)
{
    linked_t* current = queue->sentinel;
    printf("Sentinel -> ");
    fflush(stdout);
    current = current->next;
    while(current->id != SENTINEL)
    {
        printf("(%d) -> ", current->id);
        fflush(stdout);
        current = current->next;
    }
    printf("\n");
}

bool queue_is_empty(queue_t* queue)
{
    return queue->current->id == SENTINEL;   
}

void queue_reset_links(queue_t* queue, linked_t*(*callback)(int)){
    if(queue_is_empty(queue)){
        return;
    }
    int head_id = queue->current->id; 
    linked_t* head = queue_pop(queue); 
    queue_insert(queue, head);
    int id = -1; 
    while(id != head_id){
        linked_t* current = queue_pop(queue);
        if(queue_is_empty(queue)){
            int p = current->priority;
            linked_t* link = callback(p);
            
            if (link == NULL)
            { 
                //this means there are no thread of higher priority to link to
                current->context->uc_link = current->context; 
                
            }
            else
            {
                current->context->uc_link = link->context;
            }
        }
        else{
            linked_t* next_head = queue->current;
            current->context->uc_link = next_head->context; 
        }
        queue_insert(queue, current); 
        id = current->id; 
    }
}

